const Service = require('egg').Service;
const child_process = require('child_process');
const fs = require('fs')
class DeployService extends Service {
    async fetchBranchesOfRepo() {
        const {
            ownerRepoMap
        } = this.config.deploy;
        const appliactionList = new Array();
        for (const owner of Object.keys(ownerRepoMap)) {
            const cfgArray = ownerRepoMap[owner];
            for (const { repoName, repo, allowUse, port } of cfgArray) {
                try {
                    if (allowUse) {
                        let data = []
                        try {
                            const res = await this.ctx.curl(`https://gitee.com/api/v5/repos/${owner}/${repo}/branches`, {
                                method: 'get',
                                dataType: 'json'
                            })
                            data = res.data;
                            //后续考虑引入redis
                            this.modifyOrCreateCache(owner, repo, data);
                        } catch (err) {
                            this.ctx.logger.info('use cache');
                            data = this.readObjectByOwnerAndRepo(owner, repo);
                        }
                        appliactionList.push({
                            branches: data.map((data) => {
                                return {
                                    name: data.name,
                                }
                            }),
                            repoName,
                            repo,
                            port,
                            hasDeployed: Boolean(this.searchProcessIdByPort(port)),
                            curBranch: this.checkCurrentBranch(repo)
                        })
                    }

                } catch (err) {
                    return {
                        success: false,
                        appliactionList
                    }
                }
            }
        }
        return {
            success: true,
            appliactionList
        }
    }
    checkCurrentBranch(repo) {
        const {
            localRepoRoot
        } = this.config.deploy.repoRouteMap[repo]
        try {
            const route = `${localRepoRoot}/${repo}`
            if(!fs.existsSync(route)){
                throw new Error()
            }
            const checkBranchScript = `cd ${route}\n git branch -vv`
            this.logger.info(checkBranchScript)
            const branchList = child_process.execSync(checkBranchScript).toString().split('\n').filter((record) => record && record != '')
            const curBranchIndex = branchList.findIndex((branch) => branch.startsWith('*'))
            const branchName = branchList[curBranchIndex].split(' ')[1]
            if (!branchName) {
                throw new Error()
            } else {
                return branchName;
            }
        } catch (err) {
            return null
        }
    }
    deployBranch(repo, branch) {
        const {
            localRepoRoot,
            script,
            port,
            remoteUrl
        } = this.config.deploy.repoRouteMap[repo];
        try {
            const pid = this.searchProcessIdByPort(port);
            pid && this.killProcessByPid(pid);
            const deployScript = `source ${script} ${localRepoRoot} ${remoteUrl} ${repo} ${branch} ${port}`
            this.logger.info(`执行脚本:${deployScript}`);
            child_process.execSync(deployScript)
            return {
                success: true
            }
        } catch (err) {
            return {
                sucess: false
            }
        }
    }
    searchProcessIdByPort(port) {
        try {
            const stdout = child_process.execSync(`lsof -i:${port}`)
            return stdout.toString().split(' ').filter((el) => el != '')[9];
        } catch (err) {
            return null;
        }
    }
    killProcessByPid(pid) {
        child_process.execSync(`kill ${pid}`);
    }
    readObjectByOwnerAndRepo(owner, repo) {
        const {
            cacheRoute
        } = this.config.deploy;
        const cache_file_json = `${cacheRoute}/${owner}_cache.json`;
        const object = this.readJsonToObject(cache_file_json);
        return object[repo];
    }
    readJsonToObject(file) {
        const object = fs.readFileSync(file, 'utf8');
        return object ? JSON.parse(object) : {}
    }
    /**
     * 
     * @param {*} owner 
     * @param {*} repo 
     * @param {*} data 
     */
    async modifyOrCreateCache(owner, repo, data) {
        const {
            cacheRoute
        } = this.config.deploy;
        const cache_file = `${cacheRoute}/${owner}_cache.json`;
        if (!fs.existsSync(cache_file)) {
            fs.writeFile(cache_file, JSON.stringify({
                [repo]: data
            }), () => {
                this.ctx.logger.info('write cache');
            })
        } else {
            const object = this.readJsonToObject(cache_file);
            object[repo] = data;
            fs.writeFile(cache_file, JSON.stringify(object), (stderr, stdout) => {
                this.ctx.logger.info(stderr);
                this.ctx.logger.info(stdout);
            })
        }

    }
}
module.exports = DeployService;